﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DDD.Core {
    /// <summary>
    /// ポリゴンに関するアピアランスの構成要素
    /// </summary>
    /// <remarks>
    /// ポリゴンに関する要素を集めたアピアランスの構成要素の１つです。
    /// カリングとワインディングの設定を行います。
    /// </remarks>
    public class PolygonMode : Object {
        #region Field
        WindingMode winding;
        CullingMode culling;
        float lineWidth;
        #endregion

        #region Constructor
        /// <summary>
        /// コンストラクター
        /// </summary>
        /// <remarks>
        /// 初期値は、
        /// <list type="bullet">
        ///   <item><see cref="Culling"/>=<see cref="CullingMode.Back"/></item>
        ///   <item><see cref="Winding"/>=<see cref="WindingMode.CCW"/></item>
        ///   <item><see cref="LineWidth"/>=1.0</item>
        /// </list>
        /// です。ライン幅はプリミティブがラインの時だけ意味を持ちます。
        /// </remarks>
        public PolygonMode () {
            this.culling = CullingMode.Back;
            this.winding = WindingMode.CCW;
            this.lineWidth = 1;
        }
        #endregion

        #region Property
        /// <summary>
        /// ワインディング
        /// </summary>
        /// <remarks>
        /// ワインディングはポリゴンが"表"を向いているか"裏"を向いているかの判定基準です｡
        /// CCWのとき頂点が反時計回りに現れた面を"表”とみなします。CWのとき頂点が時計回りに現れた面を"表”とみなします。
        /// 面の表裏はカリングに影響します。
        /// </remarks>
        public WindingMode Winding {
            get { return this.winding; }
        }

        /// <summary>
        /// カリング
        /// </summary>
        /// <remarks>
        /// 表面か裏面のどちらかを描画しない事をカリングと言います。
        /// 通常物体は凸型で穴が開かないようにモデリングされるので、
        /// どちらか一方は隠されるので描画する必要はありません
        /// デフォルトはバックフェースカリングでつまり裏面を描画しません。
        /// "表"か"裏"かは<see cref="WindingMode"/>の設定に依存します。
        /// </remarks>
        public CullingMode Culling {
            get { return this.culling; }
        }

        /// <summary>
        /// 線幅
        /// </summary>
        /// <remarks>
        /// 描画モードがラインの時だけ意味を持ちます
        /// </remarks>
        public float LineWidth {
            get { return lineWidth; }
        }

        /// <summary>
        /// このオブジェクトが参照する全DDDオブジェクトを列挙する列挙子
        /// </summary>
        /// <remarks>
        /// 参照にnullは含まれません。同一のオブジェクトが複数出現する可能性があります。
        /// </remarks>
        public override IEnumerable<Object> References {
            get {
                return base.References;
            }
        }
        #endregion

        #region Method
        /// <summary>
        /// カリングモードの設定を行う
        /// </summary>
        /// <remark>
        /// カリングモードを<dic>Front</dic>,<dic>Back</dic>,<dic>None</dic>の中から選択します。
        /// "表"か"裏"かは<see cref="WindingMode"/>の設定に依存します。
        /// </remark>
        /// <param name="culling">カリングモード</param>
        public void SetCulling (CullingMode culling) {
            this.culling = culling;
        }

        /// <summary>
        /// ワインディングの設定を行います
        /// </summary>
        /// <remarks>
        /// ワインディングモードを<dic>CCW</dic>, <dic>CW</dic>の中から選択します。
        /// ポリゴンを構成する頂点が反時計回りに現れたとき"表"とするか、
        /// 時計回りに現れたときに"表"とするかを決定します。
        /// </remarks>
        /// <param name="winding">ワインディングモード</param>
        public void SetWinding (WindingMode winding) {
            this.winding = winding;
        }

        /// <summary>
        /// 線幅の設定を行います
        /// </summary>
        /// <remarks>
        /// 線幅はラインモードの時だけ意味を持ちます｡
        /// </remarks>
        /// <param name="width">線幅</param>
        public void SetLineWidth (float width) {
            if (width <= 0) {
                throw new ArgumentException ("Width is invalid");
            }
            this.lineWidth = width;
        }

        /// <summary>
        /// 現在のオブジェクトの状態を表す文字列を返します。
        /// </summary>
        /// <returns>現在のオブジェクトを説明する文字列</returns>
        public override string ToString () {
            return string.Format("PolygonMode: Culling={0}, Winding={1}", Culling, Winding);
        }
        #endregion


    }
}
